/*******************************************************************************
 * Copyright (c) 2006 CEA List.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     CEA List - initial API and implementation
 *******************************************************************************/
package com.cea.papyrus.tabbedproperties.section;

import java.util.ArrayList;
import java.util.Iterator;

import org.eclipse.emf.common.notify.Notifier;
import org.eclipse.gef.commands.Command;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.BusyIndicator;
import org.eclipse.swt.custom.CLabel;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.MouseListener;
import org.eclipse.swt.layout.FormAttachment;
import org.eclipse.swt.layout.FormData;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.views.properties.tabbed.ITabbedPropertyConstants;
import org.eclipse.ui.views.properties.tabbed.TabbedPropertySheetPage;
import org.eclipse.uml2.uml.Connector;
import org.eclipse.uml2.uml.Interface;
import org.eclipse.uml2.uml.Port;
import org.eclipse.uml2.uml.Property;
import org.eclipse.uml2.uml.Type;
import org.eclipse.uml2.uml.TypedElement;

import com.cea.papyrus.core.IPapyrusUIConstants;
import com.cea.papyrus.core.PapyrusPlugin;
import com.cea.papyrus.core.commands.factories.DiagramElementDeleteCommandFactory;
import com.cea.papyrus.core.editor.CommandStackUtils;
import com.cea.papyrus.core.listener.UmlElementListener;
import com.cea.papyrus.core.tabbedproperties.PropertyViewSection;
import com.cea.papyrus.core.ui.dialogs.TypedElementTreeSelectionDialog;
import com.cea.papyrus.core.utils.LookForElement;
import com.cea.papyrus.diagraminterchange2.di2.Diagram;
import com.cea.papyrus.diagraminterchange2.di2.DiagramElement;
import com.cea.papyrus.diagraminterchange2.di2.GraphEdge;
import com.cea.papyrus.diagraminterchange2.di2.GraphElement;
import com.cea.papyrus.diagraminterchange2.di2.GraphNode;

/**
 * 
 */
public class TypeSection extends PropertyViewSection {


	/** Buttons used in the section */
	protected Button browseButton, removeButton; 

	/** Associated label */
	protected CLabel label;

	/** The parent Composite */
	protected Composite parent;

	/** Listener for the delete button */
	protected MouseListener removeButtonListener;

	/** Listener for the browse button */
	protected MouseListener browseButtonListener;

	/** Image for the remove button */
	protected final org.eclipse.swt.graphics.Image remove_img = PapyrusPlugin.getImage(PapyrusPlugin.PAPYRUS_ICONS_16x16+"Delete_16x16.gif");

	/** Image for the add button */
	protected final org.eclipse.swt.graphics.Image add_img = PapyrusPlugin.getImage(PapyrusPlugin.PAPYRUS_ICONS_16x16+"Add_16x16.gif");

	/* (non-Javadoc)
	 * @see org.eclipse.ui.views.properties.tabbed.AbstractPropertySection#createControls(org.eclipse.swt.widgets.Composite, org.eclipse.ui.views.properties.tabbed.TabbedPropertySheetPage)
	 */
	@Override
	public void createControls(Composite parent, TabbedPropertySheetPage tabbedPropertySheetPage) {
		super.createControls(parent, tabbedPropertySheetPage);
		Composite composite = getWidgetFactory().createFlatFormComposite(parent);
		this.parent = parent;
		FormData data;

		//label creation
		getWidgetFactory().createCLabel(composite, "Type:"); //$NON-NLS-1$

		//value label
		label = getWidgetFactory().createCLabel(composite, "", SWT.BORDER);
		data = new FormData();
		data.left = new FormAttachment(0, STANDARD_LABEL_WIDTH+ITabbedPropertyConstants.HSPACE);
		data.right = new FormAttachment(40);
		data.top = new FormAttachment(0, ITabbedPropertyConstants.HSPACE);
		label.setLayoutData(data);

		//browseButton layout
		browseButton = getWidgetFactory().createButton(composite, "", SWT.PUSH);
		browseButton.setImage(add_img);
		data = new FormData();
		data.left = new FormAttachment(label, ITabbedPropertyConstants.HSPACE);
		data.top  = new FormAttachment(0, ITabbedPropertyConstants.HSPACE);
		browseButton.setLayoutData(data);

		//removeButton layout
		removeButton = getWidgetFactory().createButton(composite, "", SWT.PUSH);
		removeButton.setImage(remove_img);
		data = new FormData();
		data.left = new FormAttachment(browseButton, ITabbedPropertyConstants.HSPACE);
		data.top  = new FormAttachment(browseButton, 0, SWT.CENTER);
		removeButton.setLayoutData(data);

		//listeners setting
		browseButtonListener = new BrowseButtonlistener();
		browseButton.addMouseListener(browseButtonListener);
		removeButtonListener = new RemoveButtonlistener();
		removeButton.addMouseListener(removeButtonListener);
	}

	/**
	 * Refreshes the section.
	 */
	@Override
	public void refresh(){
		if(!browseButton.isDisposed()){
			Type type ;
			if (getElement() instanceof Connector)
				type = ((Connector)getElement()).getType() ;
			else 
				type= ((TypedElement)getElement()).getType();
			if(type == null){
				if(!label.isDisposed())
					label.setText("<UNDEFINED>");
				if(!removeButton.isDisposed())
					removeButton.setEnabled(false);
			}
			else{
				if(!label.isDisposed())
					label.setText(type.getQualifiedName());
				if(!removeButton.isDisposed())
					removeButton.setEnabled(true);
			}
		}
	}

	/**
	 * Listener for the RemoveButton.
	 * Specific behavior is implemented in removeButtonPressed.
	 */
	protected class RemoveButtonlistener implements MouseListener{

		/**
		 * Does nothing.
		 * @param e MouseEvent.
		 */
		public void mouseDoubleClick(MouseEvent e){
		}

		/**
		 * Does nothing.
		 * @param e MouseEvent.
		 */
		public void mouseDown(MouseEvent e){
		}

		/**
		 * Calls the removeButtonPressed() which does the job then refresh().
		 * @param e MouseEvent.
		 */
		public void mouseUp(MouseEvent e){
			removeButtonPressed();
			refresh();
		}
	}

	/**
	 * Listener for the BrowseButton.
	 * Specific behavior is implemented in browseButtonPressed.
	 */
	protected class BrowseButtonlistener implements MouseListener{

		/**
		 * Does nothing.
		 * @param e MouseEvent.
		 */
		public void mouseDoubleClick(MouseEvent e){
		}

		/**
		 * Does nothing.
		 * @param e MouseEvent.
		 */
		public void mouseDown(MouseEvent e){
		}

		/**
		 * Calls the browseButtonPressed() which does the job then refresh().
		 * @param e MouseEvent.
		 */
		public void mouseUp(MouseEvent e){
			browseButtonPressed();
			refresh();
		}
	}

	/**
	 * Behavior executed when remove button is pressed.
	 */
	protected void removeButtonPressed(){
		removeLinkedInterfaces();
		removeAllSubElementOfPart();
		((TypedElement)getElement()).setType(null);
	}

	/**
	 * Behavior executed when browse button is pressed.
	 */
	protected void browseButtonPressed(){
		final int[] result = {IDialogConstants.CANCEL_ID};
		final TypedElementTreeSelectionDialog dialog = new TypedElementTreeSelectionDialog(parent.getShell(), LookForElement.topPackage(getElement()));

		// open dialog window
		BusyIndicator.showWhile(Display.getCurrent(), new Runnable() {
			public void run() {
				result[0] = dialog.open();
			}
		});

		// if ok was pressed, and a type was selected, set new type
		if(IDialogConstants.OK_ID == result[0]){
			Type type = dialog.getResult(); 
			if(type!= null){
				//refresh port
				removeLinkedInterfaces();
				removeAllSubElementOfPart();
				//set the type
				((TypedElement)getElement()).setType(type);

				// add a listener
				if( graphicalElement!=null){
					UmlElementListener _adapter=new UmlElementListener(graphicalElement);
					((Notifier)type).eAdapters().add(_adapter);}
			}
		}
	}




	/**
	 * Disposes of the buttons and listeners. 
	 */
	public void dispose(){
		super.dispose();
		if((removeButton != null) && !removeButton.isDisposed())
			removeButton.removeMouseListener(removeButtonListener);
		if((browseButton != null) && !browseButton.isDisposed())
			browseButton.removeMouseListener(browseButtonListener);
	}

	/** 
	 * In the case of composite diagram, wee need to remove displayed interfaces when the type change
	 **/ 
	private void removeLinkedInterfaces(){
		if(diagramElement!=null){
			Diagram currentDiagram= LookForElement.getDiagram((GraphNode)diagramElement);
			final String typeDiagram = currentDiagram.getType();

			//to be apply only on port in the composite Diagram
			if( umlElement instanceof Port && typeDiagram.equals(IPapyrusUIConstants.COMPOSITE_STRUCTURE_DIAGRAM)){

				//0. the diagramElement is a label or a port?
				GraphElement di2Port=null;
				if (((GraphElement)diagramElement).getSemanticModel()!=null){
					di2Port=(GraphElement)diagramElement;
				}
				else{
					di2Port =(GraphElement) diagramElement.getSemanticParent();
				}

				//1. search all provided an required interface of the port
				ArrayList<Interface> linkedInterface= new ArrayList<Interface>();
				linkedInterface.addAll(((Port)umlElement).getProvideds());
				linkedInterface.addAll(((Port)umlElement).getRequireds());

				//loop for all interfaces
				Iterator<Interface> iterInterface=linkedInterface.iterator();

				while(iterInterface.hasNext()){
					//2. selection of an interface
					Interface anInterface=iterInterface.next();
					//3. look for all representation of this interface
					ArrayList found=LookForElement.lookForGraphElement(anInterface, currentDiagram, new ArrayList());

					//4. the graphical element already exist?
					GraphElement di2Interface =null;
					Iterator itfound=found.iterator();
					while(itfound.hasNext()){
						GraphElement currentElement= (GraphElement)itfound.next();
						if (currentElement.getSemanticParent().equals(di2Port)){
							di2Interface=currentElement;
						}
					}
					//4. we have to delete this element
					Command deletecmd=DiagramElementDeleteCommandFactory.eINSTANCE.createCommand(di2Interface);
					CommandStackUtils.getCommandStack().execute(deletecmd);
				}//End loop on uml Interface
			}//end condition to use this methods
		}
	}

	/**
	 * this method is used to remove all graphical representation of sub-element of the property when
	 * the type change in the composite diagram
	 */
	private void removeAllSubElementOfPart() {
		if(diagramElement!=null){
			Diagram currentDiagram= LookForElement.getDiagram((GraphNode)diagramElement);
			final String typeDiagram = currentDiagram.getType();

			//to be apply only on port in the composite Diagram
			if( (!(umlElement instanceof Port)) &&umlElement instanceof Property && typeDiagram.equals(IPapyrusUIConstants.COMPOSITE_STRUCTURE_DIAGRAM)){

				//0. we remove all graphEdge 
				Iterator<DiagramElement> iter= ((GraphElement)diagramElement).getContained().iterator();
				ArrayList<GraphElement> toSuppress= new ArrayList<GraphElement>();

				//0.1 get all GraphEdge
				while(iter.hasNext()){
					DiagramElement diagElement= iter.next();
					if( diagElement instanceof GraphEdge){
						toSuppress.add((GraphElement)diagElement);
					}
				}
				//0.2 remove them
				Iterator<GraphElement> iterSupp=toSuppress.iterator();
				while(iterSupp.hasNext()){
					Command com=DiagramElementDeleteCommandFactory.eINSTANCE.createCommand(iterSupp.next());
					CommandStackUtils.getCommandStack().execute(com);
				}
				//1. we remove all graphNode
				toSuppress.clear();
				//1.1 get all graphNode
				iter= ((GraphElement)diagramElement).getContained().iterator();
				while(iter.hasNext()){
					DiagramElement diagElement= iter.next();
					if( diagElement instanceof GraphNode){
						toSuppress.add((GraphElement)diagElement);
					}
				}
				//1.2 remove them
				iterSupp=toSuppress.iterator();
				while(iterSupp.hasNext()){
					Command com=DiagramElementDeleteCommandFactory.eINSTANCE.createCommand(iterSupp.next());
					CommandStackUtils.getCommandStack().execute(com);
				}

				//2. we remove displayed all ports of the part
				toSuppress.clear();
				//2.1 get all ports
				iter= ((GraphElement)diagramElement).getSemanticChild().iterator();
				while(iter.hasNext()){
					DiagramElement diagElement= iter.next();
					if( diagElement instanceof GraphNode){
						toSuppress.add((GraphElement)diagElement);
					}
				}
				//2.2 we remove them
				iterSupp=toSuppress.iterator();
				while(iterSupp.hasNext()){
					Command com=DiagramElementDeleteCommandFactory.eINSTANCE.createCommand(iterSupp.next());
					CommandStackUtils.getCommandStack().execute(com);
				}
			}//End of the condition to use it

		}
	}
}